package hello

import (
	"bytes"
	"encoding/json"
	"fmt"
	"html/template"
	"log"
	"net/http"
	"os"
	"time"
)

const (
	DefaultAddress = ":3000"
)

// 注意 Handler 是我们自己声明的，不是 net/http 里面的
type Handler interface {
	ServeHTTP(rw http.ResponseWriter, r *http.Request)
}

type HandlerFunc func(rw http.ResponseWriter, r *http.Request)

func (h HandlerFunc) ServeHTTP(rw http.ResponseWriter, r *http.Request) {
	h(rw, r)
}

type Hello struct {
	handlers []Handler
}

func New(handlers ...Handler) *Hello {
	return &Hello{
		handlers: handlers,
	}
}

// 默认实现
// Logger - 日志NewLogger()
func DefaultHello() *Hello {
	return New()
}

// 其实 Hello 也是 net/http 的中间件
// 把接收到的请求依次与 handler 匹配，直到匹配到执行
// 依次把执行[]handlers的handler的ServeHTTP方法，根据路径依次匹配，直到匹配到规定路径
func (h *Hello) ServeHTTP(rw http.ResponseWriter, r *http.Request) {
	// fmt.Println("Hello")
	// h.handlers[0].ServeHTTP(rw, r)
	for _, v := range h.handlers {
		v.ServeHTTP(rw, r)
	}
	logger(NewResponseWriter(rw), r)
}

// 把 http.Handler 转换并添加 hello.Handler
func (h *Hello) UseHandler(handler http.Handler) {
	h.Use(Wrap(handler))
}

// Wrap converts a http.Handler into a hello.Handler
func Wrap(handler http.Handler) Handler {
	return HandlerFunc(func(rw http.ResponseWriter, r *http.Request) {
		handler.ServeHTTP(rw, r)
	})
}

func (h *Hello) Use(handler Handler) {
	if handler == nil {
		panic("handler can't be bil")
	}
	h.handlers = append(h.handlers, handler)
}

func (h *Hello) Run(addr ...string) {
	l := log.New(os.Stdout, "[Hello]", 0)
	finalAddr := checkAddress(addr...)
	l.Printf(" listening on %v", finalAddr)
	l.Fatal(http.ListenAndServe(finalAddr, h))
}

func checkAddress(addr ...string) string {
	if len(addr) > 0 {
		return addr[0]
	}
	if port := os.Getenv("POST"); port != "" {
		return ":" + port
	}
	return DefaultAddress
}

type LoggerEntry struct {
	StartTime string
	Status    int
	Duration  time.Duration
	Hostname  string
	Method    string
	Path      string
}

func logger(rw http.ResponseWriter, r *http.Request) {
	start := time.Now()
	LoggerDefaultFormat := "[hello] {{.StartTime}} | {{.Status}} | {{.Hostname}} |\t {{.Duration}} | {{.Method}} {{.Path}} \n"
	temp := template.Must(template.New("helloLog").Parse(LoggerDefaultFormat))
	res := rw.(ResponseWriter)
	log := LoggerEntry{
		StartTime: start.Format("2006-01-02 15:04:05.999999"),
		Status:    res.Status(),
		Duration:  time.Since(start),
		Hostname:  r.Host,
		Method:    r.Method,
		Path:      r.URL.Path,
	}
	buff := &bytes.Buffer{}
	temp.Execute(buff, log)
	fmt.Printf(buff.String())
}

func ToJson(dict map[string]interface{}) (string, error) {
	// bstr, err := json.MarshalIndent(dict, "", "  ")
	bstr, err := json.Marshal(dict)
	return string(bstr), err
}
